<template>
  <div id="screenfull-table">
    <el-row
      :id="'Common' + tabs"
      :ref="'Common' + tabs"
      :gutter="20"
      :class="isMore?
        'common-filter-container-wrap-more':'common-filter-container-wrap'"
    >
      <div class="common-filter-container-div">
        <el-form :ref="'FormRef' + tabs" size="small" :inline="true" :model="searchParam" class="demo-form-inline">
          <template v-for="item in columns">
            <el-form-item v-if="item.search" :key="item.prop" :label="`${item.label}:`">
              <SearchFormItem :column="item" :search-param="searchParam">
                <slot v-if="item.searchSlot" :name="item.searchSlot" :scope="searchParam" />
              </SearchFormItem>
            </el-form-item>
          </template>
        </el-form>
      </div>
      <div class="submit-container">
        <el-button size="mini" type="primary" @click="onSubmit('search')">查询</el-button>
        <el-button size="mini" type="primary" @click="onSubmit('reset')">重置</el-button>
        <el-button
          v-if="showMoreButton"
          size="mini"
          class="more-button"
          type="text"
          @click="isMore=!isMore"
        >
          {{ isMore ? '收起':'展开' }}
          <i
            class="el-icon--right"
            :class="isMore?'el-icon-arrow-up':'el-icon-arrow-down'"
          />
        </el-button>
      </div>
    </el-row>
    <!--列设置按钮-->
    <div v-if="colSetting && tableData.length > 0" class="col-container">
      <div class="col-slot">
        <slot name="btns" :row="{selectList:selectList}" />
      </div>
      <div v-if="columnsSetting" class="operation-container">
        <screenfull id="screenfull" dom="screenfull-table" class="right-menu-item hover-effect" />
        <el-dropdown trigger="click">
          <i class="el-icon-setting" />
          <!-- <el-button icon="el-icon-setting" size="mini" type="text" /> -->
          <el-dropdown-menu slot="dropdown" class="col-dropdown">
            <span class="title">列设置</span>
            <!-- <el-tree :data="columns" :props="defaultProps" :allow-drop="allowDrop" @node-drop="handleDrop">
            <span slot-scope="{ node, data }" class="tree-table-setting">
              <el-switch v-model="data.show" size="small" :disabled="data.disabled" @change="saveTableColumns" />
              <span>{{ node.label }}</span>
            </span>
          </el-tree> -->
            <el-tree
              ref="tree"
              :key="treeKey"
              show-checkbox
              node-key="prop"
              :data="renderColoums"
              :props="defaultProps"
              :default-checked-keys="defaultCheckedKeys"
              @check-change="currentChange"
            />
          </el-dropdown-menu>
        </el-dropdown>
      </div>
    </div>
    <!--表格-->
    <div>
      <el-table
        ref="table"
        :key="tableKey"
        v-loading="tableLoading"
        :data="tableData"
        :row-style="{ height: '40px' }"
        :cell-style="{ }"
        :header-cell-style="{ height: '40px', padding: 0, background: '#f6f8fa', color: '#333' }"
        size="mini"
        tooltip-effect="dark"
        v-bind="tableProps"
        @select="handleInitiativeSelect"
        @select-all="handleInitiativeAllSelect"
        @row-click="handelTableClick"
        @selection-change="handleSelectionChange"
        @header-dragend="surverWidth"
      >
        <template
          v-for="item in columns"
        >
          <template v-if="item.show && item.prop === 'selection'">
            <el-table-column :key="item.prop" align="center" :resizable="false" type="selection" />
          </template>
          <template v-else-if="item.show && item.prop === 'actions'">
            <!-- 固定列 -->
            <el-table-column :key="item.prop" fixed="right" align="center" :label="item.label ? 'item.label' : '操作'" :width="item.width" :resizable="false">
              <div slot-scope="scope" class="col-slot">
                <slot name="actions" :scope="{...scope}" />
              </div>
            </el-table-column>
          </template>
          <template v-else>
            <el-table-column
              v-if="item.show"
              :key="item.prop"
              align="center"
              show-overflow-tooltip
              :prop="item.prop"
              :sortable="item.sortable"
              :label="item.label"
              :width="item.width"
              :resizable="false"
            >
              <template slot="header" slot-scope="scope">
                <el-tooltip :content="item.label" placement="top">
                  <div :ref="'refName' + scope.$index" class="title title-header">
                    {{ item.label }}
                  </div>
                </el-tooltip>
                <!-- <el-popover placement="bottom" title="请选择" width="200" trigger="hover">
                  <div slot="reference" class="search-header">
                      <i class="search-icon el-icon-search"></i>
                  </div>
                  <div>单项搜索预留</div>
                </el-popover> -->
              </template>
              <template slot-scope="scope">
                <span v-if="item.slot">
                  <slot :name="item.slot" :scope="scope" />
                </span>
                <span v-else-if="item.type === 'time' && scope.row[item.prop]">{{ dayjs(scope.row[item.prop]).format('YYYY年MM月DD日') }}</span>
                <span v-else>{{ renderEnum(scope, item) ? renderEnum(scope, item) : '-' }}</span>
              </template>
            </el-table-column>
          </template>
        </template>
      </el-table>
      <slot :scope="pageable" name="pagination">
        <Pagination
          v-if="pagination && tableData.length > 0"
          :pageable="pageable"
          :handle-size-change="handleSizeChange"
          :handle-current-change="handleCurrentChange"
        />
      </slot>
    </div>
  </div>
</template>
<script>
import { debounce } from '@/utils'
import SearchFormItem from './SearchFormItem'
import Screenfull from '@/components/Screenfull'

import Pagination from './Pagination'
import dayjs from 'dayjs'
/**
columns 可以查看 element 组件库配置， 这里列出常用项
prop: 'name', // 对应列内容的字段名
label: '姓名', // 显示的标题
width: 90, // 对应列的宽度
resizable: true, // 对应列是否可以通过拖动改变宽度（需要在 el-table 上设置 border 属性为真） , 暂时启用， 父子组件传会报错
show: true, // 展示与隐藏
sortable: true, // 对应列是否可以排序
disabled: true // 是否禁用显隐
 */
export default {
  components: {
    SearchFormItem,
    Screenfull,
    Pagination
  },
  props: {
    // api 必传
    requestApi: {
      type: Function,
      required: true
    },
    // 初始化请求参数 非必传, 这里的参数以后没一次请求都会携带
    initParam: {
      type: Object,
      default: () => {}
    },
    // 搜索部分的参数处理 非必传
    searchHandler: {
      type: Function,
      default: () => false
    },
    // 对返回数据进行进一步处理 非必传
    dataCallBack: {
      type: [Function, undefined],
      default: undefined
    },
    // 需要选中的项， 非必传 选中的时候，过滤出id或key字段 如  [ 308, 306 ] 赋值给这个数组 ， 子组件会侦听，变化以后重置子组件的选中。 不影响后续选中
    setSelectList: {
      type: Array,
      default: () => []
    },
    // 基于 tabs ， 动态监视不同 tabs 下 form 的高度（多标签页时候适用，只有一页的可不传）
    tabs: {
      type: String,
      default: '1'
    },
    columns: {
      type: Array,
      default: () => []
    },
    // 需要头传给 table 组件的属性
    tableProps: {
      type: Object,
      default: () => {}
    },
    // 是否展示列设置
    columnsSetting: {
      type: Boolean,
      default: true
    },
    // 是否展示表格上方功能这一栏
    colSetting: {
      type: Boolean,
      default: true
    },
    // 用户主动勾选触发
    initiativeSelect: {
      type: Function,
      default: () => {}
    },
    // 表格loading
    loading: {
      type: Boolean,
      default: () => false
    },
    pagination: {
      type: Boolean,
      default: true
    }
  },
  data() {
    return {
      // 表格key
      tableKey: 1,
      // 列设置组件key
      treeKey: 1,
      // 传输给父组件的各类状态
      selectList: [],
      // 表格数据
      tableData: [],
      // 选中表格的行
      currentData: {},
      // 列设置中 tree配置
      defaultProps: {
        children: 'children',
        label: 'label'
      },
      defaultCheckedKeys: [], // 列设置默认选中的节点
      showMoreButton: false,
      searchParam: {}, // 搜索项参数
      resetSearchParams: {}, // 需要过滤以后得搜索项参数
      isMore: false, // 是否是展示更多的 状态
      tableLoading: false, // 表格 loading
      renderColoums: [],
      dayjs,
      pageable: {
        // 当前页数
        pageNum: 1,
        // 每页显示条数
        pageSize: 10,
        // 总条数
        total: 0
      }
    }
  },
  computed: {
  },
  watch: {
    // 父组件控制选中状态
    setSelectList() {
      // 先清空
      this.$refs.table.clearSelection()
      this.setSelectList.forEach((item) => {
        if (this.tableData.find((it) => it.id === item)) {
          this.$refs.table.toggleRowSelection(
            this.tableData.find((it) => it.id === item),
            true
          )
        }
      })
    }
  },
  created() {
    this.columnsHanlder()
    this.defaultCheckedKeys = this.columns.map(item => item.prop)
    this.toShowMore()
    window.onresize = () => {
      this.toShowMore()
    }
    this.getTableList()
  },
  // 解决 自定义列 + 固定列 导致显示问题  参考 https://blog.csdn.net/qq_36126031/article/details/121970398
  updated() {
    this.$refs.table.doLayout()
  },
  mounted() {
    this.init()
  },
  methods: {
    // 处理 列设置的 columns 去掉 多选和 操作部分
    columnsHanlder() {
      this.renderColoums = this.columns.filter(item => item.prop !== 'selection' && item.prop !== 'actions')
    },
    // 获取表格数据， params 为搜索部分参数，如果有， 则不使用 初始化参数
    async getTableList() {
      // 初始化参数 和分页信息
      this.tableLoading = true
      const useParams = Object.assign({}, this.resetSearchParams, this.initParam, this.pagination ? this.pageable : {})
      console.log('useParams', useParams)
      let { data } = await this.requestApi(useParams)
      this.dataCallBack && (data = this.dataCallBack(data))
      this.pagination && (this.pageable.total = data.total)
      this.tableData = data.list
      setTimeout(() => {
        this.tableLoading = false
      }, 1000)
    },
    currentChange(e, d) {
      this.columns.find(it => it.prop === e.prop).show = d
    },
    init() {
      // 判断本地是否有表格配置数据 ？ 加载 :  忽略
      // 获取表格数据
      // 重设表格高度
    },
    allowDrop(draggingNode, dropNode, type) {
      // 仅允许Tree节点上下拖动
      return type !== 'inner'
    },
    // Tree 拖动时更新表格
    handleDrop() {
      this.tableKey++
      // 保存表格配置
      this.saveTableColumns()
    },
    // 重置表格列设置
    resetTable() {
      this.$refs.table.clearSelection()
      this.pageable.pageNum = 1
      this.resetSearchParams = {}
      this.searchParam = {}
      this.renderColoums.map((item) => {
        item.show = true
      })
      this.getTableList()
      this.treeKey++
      // ... 忽略
    },
    // 显示隐藏切换 && 保存表格配置
    saveTableColumns() {
      // setStorage 封装了 localStorage
      // setStorage('clueTable', this.columns)
    },
    // 用户勾选行才触发
    handleInitiativeSelect(val) {
      this.initiativeSelect(val)
    },
    // 用户勾选全选才触发
    handleInitiativeAllSelect(val) {
      this.initiativeSelect(val)
    },
    // 选中表格行
    handelTableClick(row) {
      this.currentData = row
    },
    // table多选操作
    handleSelectionChange(val) {
      console.log('多选', val)
      this.selectList = val
    },
    // 表头拖动事件
    surverWidth(newWidth, oldWidth, column, event) {
      this.columns = this.columns.map(v => {
        if (v.prop === column.property) v.width = newWidth
        return v
      })
      this.saveTableColumns()
    },
    // 关注与编辑操作
    clueTableRowClick(val, type) {
      // ... 省略业务逻辑
    },
    // 处理搜索项部分
    initSearchParams() {

    },
    onSubmit(type) {
      this.pageable.pageNum = 1
      switch (type) {
        case 'search':
          this.resetSearchParams = this.searchHandler(this.searchParam) ? this.searchHandler(this.searchParam) : this.searchParam
          this.getTableList()
          break
        case 'reset':
          this.resetSearchParams = {}
          this.searchParam = {}
          this.getTableList()
          break
      }
    },
    // 如果传了枚举值，渲染的时候根据枚举值 区数据中的数据进行 枚举值映射，使用 逗号隔开。
    renderEnum(scope, item) {
      const current = scope.row[item.prop]
      // 没有 enum 则不需要映射, 没有值 返回原值
      if (!item?.enum || current === undefined || current === null) {
        return current
      }
      // 如果不是数组，直接拿取映射
      if (!Array.isArray(current)) {
        return item.enum.find((o) => o.value === current)?.label
      }
      // 如果数组长度是 0， 返回 undefined ，以免后面渲染  '[]'
      if (current?.length === 0) {
        return undefined
      }
      return current.map((it) => item.enum.find((o) => o.value === it).label).join(',')
    },
    // 页面初始化时候调用，以及窗口size调整 以及侧边菜单变化时调用
    toShowMore: debounce(function() {
      this.$nextTick(() => {
        if (!this.$refs.FormRef) return
        const formHeight = window.getComputedStyle(this.$refs.FormRef.$el)
          .getPropertyValue('height')
          .replace('px', '')
        if (formHeight < 50) {
          this.showMoreButton = false
        } else {
          this.showMoreButton = true
        }
      })
    }, 300),
    // 分页部分
    handleSizeChange(val) {
      this.pageable.pageNum = 1
      this.pageable.pageSize = val
      this.getTableList()
    },
    handleCurrentChange(val) {
      this.pageable.pageNum = val
      this.getTableList()
    }
  }
}

</script>
<style  lang="scss" scoped>
.col-container{
  display:flex;
  justify-content: space-between;
  padding: 5px
}
.col-slot{
  >button{
    margin-right:10px
  }
}
.col-dropdown{
  padding: 10px;
  .el-tree-node__expand-icon{
    display: none
  }
  .el-switch{
    margin-right: 5px
  }
}

.common-filter-container-wrap, .common-filter-container-wrap-more {
  display: flex;
}
.common-filter-container-wrap .common-filter-container-div {
  max-width: 85%;
  min-width: 400px;
  width: fit-content;
  padding: 18px 0 0 18px !important;
  max-height: 63px;
  overflow: hidden;
  white-space: wrap;
  position: relative;
  transition-property: max-height;
  transition-duration: 0.5s;
  transition-timing-function: ease;
}
.common-filter-container-wrap-more .common-filter-container-div {
  padding: 18px 0 0 18px !important;
  max-width: 85%;
  max-height: 1000px;
  white-space: wrap;
  position: relative;
  transition-property: max-height;
  transition-duration: 2s;
  transition-timing-function: ease;
}
.submit-container{
  width: 200px;
  position: absolute;
  right: 0;
  padding: 18px 0
}
.demo-form-inline .el-form-item__label {
  white-space: nowrap;
  font-size: 13px;
}
.common-filter-container-wrap >>> .el-form-item {
  white-space: nowrap;
}
.common-filter-container-more >>> .el-form-item {
  white-space: nowrap;
}
.common-filter-container-more .el-form-item__label {
  white-space: nowrap;
  font-size: 13px;
}
.operation-container{
  display: flex;
  cursor: pointer;
  align-items:center;
  >div{
    margin-left: 5px
  }
}
#screenfull-table{
  background: white
}
</style>
